#include <stdio.h>
#include <omp.h>

// 模拟工作函数，打印当前线程及处理的循环变量信息
void work(int i, int j) {
    printf("    work(%d, %d) executed by Thread %d\n", i, j, omp_get_thread_num());
}

// 1. 正确的嵌套循环
// 外层循环用 parallel+for 分发迭代，内层循环在每次外层迭代时启动一个新的并行区域处理内层迭代
void correct_nested_loops(int n) {
    int i, j;
    printf("=== Correct Nested Loops ===\n");
    #pragma omp parallel default(shared)
    {
        #pragma omp for
        for (i = 0; i < n; i++) {
            printf("Outer loop: Thread %d processing i = %d\n", omp_get_thread_num(), i);
            // 为避免直接嵌套两个 for 指令，内层循环放在新的 parallel 区域中
            #pragma omp parallel default(shared)
            {
                #pragma omp for
                for (j = 0; j < n; j++) {
                    work(i, j);
                }
            }
        }
    }
}

// 2. 循环区域与 single 区域分离
// 先用 for 分发循环，然后再单独用 single 指令执行特定操作，避免单一区域与循环区域紧密嵌套
void correct_loop_single(int n) {
    int i;
    printf("\n=== Correct Loop and Single Region Separation ===\n");
    #pragma omp parallel default(shared)
    {
        // 先执行循环
        #pragma omp for
        for (i = 0; i < n; i++) {
            printf("Loop: Thread %d processing i = %d\n", omp_get_thread_num(), i);
        }
        // 循环结束后，单独进入 single 区域
        #pragma omp single
        {
            printf("Single: Thread %d executing single region\n", omp_get_thread_num());
        }
    }
}

// 3. 正确的屏障使用：将屏障放在循环区域之外
void correct_barrier_in_loop(int n) {
    int i;
    printf("\n=== Correct Barrier with Loop Regions ===\n");
    #pragma omp parallel default(shared)
    {
        // 第一部分循环
        #pragma omp for
        for (i = 0; i < n; i++) {
            printf("Before barrier: Thread %d processing i = %d\n", omp_get_thread_num(), i);
        }
        // 屏障放在循环区域之外，确保所有线程完成第一部分后再继续
        #pragma omp barrier
        // 第二部分循环
        #pragma omp for
        for (i = 0; i < n; i++) {
            printf("After barrier: Thread %d processing i = %d\n", omp_get_thread_num(), i);
        }
    }
}

// 4. 临界区中正确使用屏障：屏障放在临界区之外，避免死锁
void correct_barrier_in_critical() {
    printf("\n=== Correct Barrier with Critical Region ===\n");
    #pragma omp parallel default(shared)
    {
        #pragma omp critical
        {
            printf("Inside critical (first): Thread %d executing work1\n", omp_get_thread_num());
        }
        // 屏障放在临界区之外
        #pragma omp barrier
        #pragma omp critical
        {
            printf("Inside critical (second): Thread %d executing work2\n", omp_get_thread_num());
        }
    }
}

// 5. 单一（single）区域中正确使用屏障：屏障放在 single 区域之外
void correct_barrier_in_single() {
    printf("\n=== Correct Barrier with Single Region ===\n");
    #pragma omp parallel default(shared)
    {
        #pragma omp single
        {
            printf("Inside single (first): Thread %d executing work1\n", omp_get_thread_num());
        }
        // 屏障放在 single 区域之外
        #pragma omp barrier
        #pragma omp single
        {
            printf("Inside single (second): Thread %d executing work2\n", omp_get_thread_num());
        }
    }
}

int main() {
    int n = 4;
    // 启用嵌套并行（若需要内层 parallel 能够启动新线程）
    omp_set_nested(1);

    // 演示正确的嵌套循环
    correct_nested_loops(n);
    // 演示循环区域与 single 区域分离
    correct_loop_single(n);
    // 演示屏障的正确使用
    correct_barrier_in_loop(n);
    // 演示临界区中正确使用屏障
    correct_barrier_in_critical();
    // 演示 single 区域中正确使用屏障
    correct_barrier_in_single();

    printf("\nPress Enter to exit...\n");
    getchar();
    return 0;
}
